Popular Searches
Popular Course Categories
Popular Courses

Building a Database-Driven MVC Web Application

Building a Database-Driven MVC Web Application

JavaBeans and MVC-Based Web Applications

Building a Database-Driven MVC Web Application

Course: Advanced Java Training

Topic: Building a Database-Driven MVC Web Application

Course Link: Advanced Java Training Course

Demo Link: Register for a Course Demo

JustAcademy Website: Visit JustAcademy


1. Introduction to Database-Driven MVC Web Applications

A database-driven MVC web application is a Java web application that stores, retrieves, updates, and deletes information in a database while following the Model-View-Controller (MVC) architectural pattern. MVC separates the application's data and business logic from request handling and presentation, making the code easier to maintain, test, and extend.

For example, a student management system can allow users to register students, view student details, update records, and delete existing entries. A Servlet receives the request, the service layer applies business rules, the DAO communicates with the database, and a JSP page displays the result.

Learning Objectives

  • Understand the architecture of a database-driven MVC application.
  • Connect a Java web application to MySQL using JDBC.
  • Create JavaBeans to represent application data.
  • Implement Servlets as controllers and JSP pages as views.
  • Build DAO methods for database CRUD operations.
  • Use prepared statements for parameterized SQL queries.
  • Validate user input and handle database errors.
  • Apply security and maintainability best practices.

2. Understanding MVC Architecture

MVC stands for Model, View, and Controller. Each component has a specific responsibility within the application.

2.1 Model

The Model represents application data and business operations. In a database-driven Java application, it may include JavaBeans, service classes, and DAO classes.

  • JavaBean: Represents structured data, such as a student record.
  • Service class: Applies business rules and coordinates operations.
  • DAO class: Executes database queries and maps database records to Java objects.

2.2 View

The View presents information to the user. JSP pages commonly provide the user interface in traditional Java web applications. They display forms, records, validation messages, and operation results.

2.3 Controller

The Controller receives HTTP requests and coordinates the workflow. Java Servlets commonly perform this role by reading request parameters, calling service methods, storing results in request attributes, and forwarding or redirecting to the appropriate destination.

Component Technology Responsibility
View JSP, HTML, CSS Displays forms and database records.
Controller Servlet Handles HTTP requests and coordinates processing.
Model JavaBean and service classes Represents data and applies business rules.
Data Access DAO and JDBC Executes SQL statements and maps results.
Database MySQL or another relational database Stores application data persistently.

3. Architecture and Request Flow

User / Browser
      |
      | HTTP Request
      v
Servlet Controller
      |
      | Calls service method
      v
Service Layer
      |
      | Calls DAO method
      v
DAO / JDBC
      |
      | SQL Query
      v
Relational Database
      |
      | Query Result
      v
DAO → Service → Controller
      |
      | Request Attributes
      v
JSP View
      |
      | HTML Response
      v
User / Browser

This architecture keeps database operations out of JSP pages. The Controller coordinates the request, the service layer applies business rules, and the DAO manages persistence.

4. Project Example: Student Management System

In this tutorial, we will create a basic Student Management System using Java Servlets, JSP, JavaBeans, JDBC, and MySQL. The application will support adding, listing, and deleting student records.

4.1 Application Features

  • Add a student with a name and email address.
  • Save student records in a MySQL database.
  • Display all saved student records.
  • Delete a student using their ID.
  • Validate user input on the server.
  • Separate database operations from request handling and presentation.

4.2 Suggested Project Structure

StudentMVC/
├── src/main/java/
│   └── com/example/
│       ├── model/
│       │   └── Student.java
│       ├── util/
│       │   └── DBConnection.java
│       ├── dao/
│       │   └── StudentDAO.java
│       ├── service/
│       │   └── StudentService.java
│       └── controller/
│           └── StudentServlet.java
├── src/main/webapp/
│   ├── index.jsp
│   └── WEB-INF/
│       └── views/
│           └── students.jsp
└── pom.xml

The examples below use the Jakarta Servlet API and are intended for a compatible Jakarta EE 9 or later servlet container. Older Java EE applications may use javax.servlet imports instead of jakarta.servlet. Keep the Servlet API, container, JSTL, and JDBC dependencies compatible with the selected environment.

5. Step 1: Create the Database and Table

First, create a database and a table to store student information. This example uses MySQL.

CREATE DATABASE student_mvc_db;

USE student_mvc_db;

CREATE TABLE students (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100) NOT NULL,
    email VARCHAR(254) NOT NULL UNIQUE,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Explanation

  • CREATE DATABASE creates the database.
  • id uniquely identifies each student record.
  • AUTO_INCREMENT generates an ID for each new record.
  • name stores the student's name.
  • email stores the student's email address.
  • NOT NULL ensures that required columns cannot be null.
  • UNIQUE prevents duplicate email addresses.
  • created_at records the creation timestamp.

Database constraints provide an additional layer of data integrity. Application-level validation is still necessary to return helpful messages to users.

6. Step 2: Configure the JDBC Driver

JDBC (Java Database Connectivity) allows Java applications to communicate with relational databases. In a Maven project, add MySQL Connector/J to your pom.xml.

<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <version>9.4.0</version>
</dependency>

The version above is an example. Check compatibility with your Java runtime and choose an appropriate supported driver version before using it in a production application.

7. Step 3: Create the Student JavaBean

Create Student.java inside the com.example.model package. This class represents a student record.

package com.example.model;

import java.io.Serializable;

public class Student implements Serializable {
    private static final long serialVersionUID = 1L;

    private int id;
    private String name;
    private String email;

    public Student() {
    }

    public Student(int id, String name, String email) {
        this.id = id;
        this.name = name;
        this.email = email;
    }

    public Student(String name, String email) {
        this.name = name;
        this.email = email;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}

Explanation

  • The private fields represent the data stored in the database.
  • Getter methods return the values of object properties.
  • Setter methods allow properties to be updated.
  • The public no-argument constructor follows conventional JavaBean usage.
  • The parameterized constructors simplify object creation.
  • Serializable supports Java serialization where needed, although it is not mandatory for every JavaBean.

8. Step 4: Create the Database Connection Utility

Create DBConnection.java in the com.example.util package. This utility provides JDBC connections for DAO operations.

package com.example.util;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public final class DBConnection {

    private static final String URL =
        System.getenv().getOrDefault(
            "DB_URL",
            "jdbc:mysql://localhost:3306/student_mvc_db"
        );

    private static final String USER = System.getenv("DB_USER");
    private static final String PASSWORD =
        System.getenv("DB_PASSWORD");

    private DBConnection() {
    }

    public static Connection getConnection()
            throws SQLException {

        if (USER == null || PASSWORD == null) {
            throw new SQLException(
                "Database credentials are not configured."
            );
        }

        return DriverManager.getConnection(
            URL, USER, PASSWORD
        );
    }
}

Explanation

  • DriverManager.getConnection() creates a database connection.
  • The JDBC URL identifies the database host, port, and database name.
  • Credentials are read from environment variables instead of being hard-coded.
  • SQLException communicates connection or database errors to the calling code.
  • A centralized connection utility avoids repeating configuration in every DAO method.

Security note: Configure DB_URL, DB_USER, and DB_PASSWORD in the deployment environment. Do not commit production credentials to source control. For production applications, prefer a managed or configured connection pool using a DataSource where available.

9. Step 5: Create the StudentDAO Class

The Data Access Object (DAO) pattern separates database operations from business logic and presentation. The DAO executes SQL statements and maps database rows to Java objects.

Create StudentDAO.java inside the com.example.dao package.

package com.example.dao;

import com.example.model.Student;
import com.example.util.DBConnection;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public class StudentDAO {

    public Student create(Student student) throws SQLException {
        String sql =
            "INSERT INTO students (name, email) VALUES (?, ?)";

        try (Connection connection = DBConnection.getConnection();
             PreparedStatement statement = connection.prepareStatement(
                 sql, Statement.RETURN_GENERATED_KEYS)) {

            statement.setString(1, student.getName());
            statement.setString(2, student.getEmail());

            int affectedRows = statement.executeUpdate();

            if (affectedRows != 1) {
                throw new SQLException("Student creation failed.");
            }

            try (ResultSet keys = statement.getGeneratedKeys()) {
                if (keys.next()) {
                    student.setId(keys.getInt(1));
                } else {
                    throw new SQLException(
                        "Student ID was not generated."
                    );
                }
            }
        }

        return student;
    }

    public List<Student> findAll() throws SQLException {
        String sql =
            "SELECT id, name, email FROM students ORDER BY id DESC";

        List<Student> students = new ArrayList<>();

        try (Connection connection = DBConnection.getConnection();
             PreparedStatement statement =
                 connection.prepareStatement(sql);
             ResultSet resultSet = statement.executeQuery()) {

            while (resultSet.next()) {
                Student student = new Student(
                    resultSet.getInt("id"),
                    resultSet.getString("name"),
                    resultSet.getString("email")
                );

                students.add(student);
            }
        }

        return students;
    }

    public boolean deleteById(int id) throws SQLException {
        String sql = "DELETE FROM students WHERE id = ?";

        try (Connection connection = DBConnection.getConnection();
             PreparedStatement statement =
                 connection.prepareStatement(sql)) {

            statement.setInt(1, id);
            return statement.executeUpdate() == 1;
        }
    }
}

Understanding the DAO Methods

Method Purpose SQL Operation
create() Saves a new student record. INSERT
findAll() Retrieves all student records. SELECT
deleteById() Deletes a student by ID. DELETE

Important JDBC Concepts

  • Connection: Represents a connection to the database.
  • PreparedStatement: Executes parameterized SQL statements.
  • ResultSet: Represents rows returned by a query.
  • executeUpdate(): Executes INSERT, UPDATE, or DELETE statements and returns the affected-row count.
  • executeQuery(): Executes a SELECT query and returns a ResultSet.
  • try-with-resources: Closes JDBC resources automatically when processing finishes.

Prepared statements help prevent SQL injection by separating SQL structure from supplied values. The application should also handle database constraint violations, such as a duplicate email address, and return an appropriate user-facing message.

10. Step 6: Create the Service Layer

The service layer contains application-level business rules and coordinates operations between the Controller and DAO. This keeps business logic out of Servlets.

Create StudentService.java in the com.example.service package.

package com.example.service;

import com.example.dao.StudentDAO;
import com.example.model.Student;

import java.sql.SQLException;
import java.util.List;

public class StudentService {

    private final StudentDAO studentDAO;

    public StudentService() {
        this.studentDAO = new StudentDAO();
    }

    public Student registerStudent(String name, String email)
            throws SQLException {

        if (name == null || name.trim().isEmpty()) {
            throw new IllegalArgumentException(
                "Student name is required."
            );
        }

        if (email == null || email.trim().isEmpty()) {
            throw new IllegalArgumentException(
                "Email address is required."
            );
        }

        name = name.trim();
        email = email.trim();

        if (name.length() > 100) {
            throw new IllegalArgumentException(
                "Student name must not exceed 100 characters."
            );
        }

        if (email.length() > 254
                || !email.matches("^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$")) {
            throw new IllegalArgumentException(
                "Enter a valid email address."
            );
        }

        Student student = new Student(name, email);
        return studentDAO.create(student);
    }

    public List<Student> getAllStudents()
            throws SQLException {
        return studentDAO.findAll();
    }

    public boolean removeStudent(int id)
            throws SQLException {

        if (id <= 0) {
            throw new IllegalArgumentException(
                "Student ID must be a positive number."
            );
        }

        return studentDAO.deleteById(id);
    }
}

Benefits of a Service Layer

  • Centralizes business validation.
  • Reduces the amount of logic inside Servlets.
  • Allows business operations to be reused.
  • Makes business logic easier to unit test.
  • Provides a suitable place to coordinate database transactions for operations involving multiple changes.

The email expression is only a basic format check. It does not verify that the address exists or belongs to the user. More demanding applications should use suitable validation rules and, where needed, email verification.

11. Step 7: Create the Servlet Controller

The Servlet receives browser requests and calls the service layer. The following example supports listing students, adding a student, and deleting a student.

Create StudentServlet.java in the com.example.controller package.

package com.example.controller;

import com.example.model.Student;
import com.example.service.StudentService;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.sql.SQLException;
import java.util.List;

@WebServlet("/students")
public class StudentServlet extends HttpServlet {

    private StudentService studentService;

    @Override
    public void init() {
        studentService = new StudentService();
    }

    @Override
    protected void doGet(HttpServletRequest request,
                         HttpServletResponse response)
            throws ServletException, IOException {

        String action = request.getParameter("action");

        if ("delete".equals(action)) {
            response.sendError(
                HttpServletResponse.SC_METHOD_NOT_ALLOWED,
                "Use POST to delete a student."
            );
            return;
        }

        showStudents(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request,
                          HttpServletResponse response)
            throws ServletException, IOException {

        request.setCharacterEncoding("UTF-8");

        String action = request.getParameter("action");

        try {
            if ("create".equals(action)) {
                String name = request.getParameter("name");
                String email = request.getParameter("email");

                studentService.registerStudent(name, email);

                response.sendRedirect(
                    request.getContextPath()
                    + "/students?message=created"
                );
                return;
            }

            if ("delete".equals(action)) {
                String idValue = request.getParameter("id");

                int id;
                try {
                    id = Integer.parseInt(idValue);
                } catch (NumberFormatException ex) {
                    response.sendError(
                        HttpServletResponse.SC_BAD_REQUEST,
                        "Invalid student ID."
                    );
                    return;
                }

                boolean deleted = studentService.removeStudent(id);

                response.sendRedirect(
                    request.getContextPath()
                    + "/students?message="
                    + (deleted ? "deleted" : "notfound")
                );
                return;
            }

            response.sendError(
                HttpServletResponse.SC_BAD_REQUEST,
                "Unknown action."
            );

        } catch (IllegalArgumentException ex) {
            request.setAttribute("error", ex.getMessage());
            showStudents(request, response);

        } catch (SQLException ex) {
            log("Database operation failed.", ex);

            response.sendError(
                HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
                "The database operation could not be completed."
            );
        }
    }

    private void showStudents(HttpServletRequest request,
                              HttpServletResponse response)
            throws ServletException, IOException {

        try {
            List<Student> students =
                studentService.getAllStudents();

            request.setAttribute("students", students);
            request.setAttribute(
                "message",
                request.getParameter("message")
            );

            request.getRequestDispatcher(
                "/WEB-INF/views/students.jsp"
            ).forward(request, response);

        } catch (SQLException ex) {
            log("Unable to retrieve student records.", ex);

            response.sendError(
                HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
                "Student records are temporarily unavailable."
            );
        }
    }
}

How the Controller Works

  • @WebServlet("/students") maps the URL to the Servlet.
  • doGet() retrieves and displays student records.
  • doPost() processes create and delete actions.
  • The service layer performs validation and calls the DAO.
  • Request attributes pass the student list and messages to the JSP.
  • Redirects after successful changes follow the Post/Redirect/Get pattern.
  • Unexpected database errors are logged on the server while the browser receives a generic message.

Production note: Add CSRF protection to state-changing forms and enforce authorization checks on the server. The action parameter identifies a requested operation; it does not establish whether a user is permitted to perform it.

12. Step 8: Create the JSP View

Create students.jsp inside WEB-INF/views. This page displays a registration form and the student records returned by the Controller.

<%@ page contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" %>
<%@ taglib prefix="c" uri="jakarta.tags.core" %>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Student Management</title>
</head>
<body>
    <h1>Student Management System</h1>

    <c:if test="${not empty error}">
        <p role="alert">
            <c:out value="${error}"/>
        </p>
    </c:if>

    <c:if test="${message == 'created'}">
        <p>Student registered successfully.</p>
    </c:if>

    <c:if test="${message == 'deleted'}">
        <p>Student deleted successfully.</p>
    </c:if>

    <c:if test="${message == 'notfound'}">
        <p>No matching student was found.</p>
    </c:if>

    <h2>Add Student</h2>

    <form method="post"
          action="${pageContext.request.contextPath}/students">
        <input type="hidden" name="action" value="create">

        <label for="name">Name:</label>
        <input type="text" id="name" name="name"
               maxlength="100" required>
        <br><br>

        <label for="email">Email:</label>
        <input type="email" id="email" name="email"
               maxlength="254" required>
        <br><br>

        <button type="submit">Add Student</button>
    </form>

    <h2>Student Records</h2>

    <c:choose>
        <c:when test="${empty students}">
            <p>No student records are available.</p>
        </c:when>

        <c:otherwise>
            <table border="1" cellpadding="8" cellspacing="0">
                <thead>
                    <tr>
                        <th>ID</th>
                        <th>Name</th>
                        <th>Email</th>
                        <th>Action</th>
                    </tr>
                </thead>
                <tbody>
                    <c:forEach var="student" items="${students}">
                        <tr>
                            <td>
                                <c:out value="${student.id}"/>
                            </td>
                            <td>
                                <c:out value="${student.name}"/>
                            </td>
                            <td>
                                <c:out value="${student.email}"/>
                            </td>
                            <td>
                                <form method="post"
                                      action="${pageContext.request.contextPath}/students">
                                    <input type="hidden"
                                           name="action" value="delete">
                                    <input type="hidden"
                                           name="id"
                                           value="${student.id}">
                                    <button type="submit">
                                        Delete
                                    </button>
                                </form>
                            </td>
                        </tr>
                    </c:forEach>
                </tbody>
            </table>
        </c:otherwise>
    </c:choose>
</body>
</html>

Understanding the JSP Elements

  • c:if conditionally displays messages.
  • c:choose and c:when select which content to display.
  • c:forEach iterates over the collection of Student objects.
  • c:out escapes HTML-sensitive characters in displayed values by default.
  • The hidden action field identifies the requested operation.
  • The delete form uses POST rather than a GET link to request a state-changing action.

Dependency note: Include a JSTL/Jakarta Tags implementation compatible with the JSP version used by your container. The URI jakarta.tags.core is used by modern Jakarta Tags versions; older applications may require a different URI.

Security note: HTML escaping does not replace CSRF protection or authorization. Add CSRF tokens to state-changing forms and verify permissions on the server before inserting or deleting records.

13. Step 9: Add an Application Entry Point

Create index.jsp in the web application root to provide a simple starting page.

<%@ page contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Student MVC Application</title>
</head>
<body>
    <h1>Welcome to Student MVC</h1>
    <p>Manage student records using a database-driven MVC application.</p>
    <p>
        <a href="${pageContext.request.contextPath}/students">
            Open Student Management
        </a>
    </p>
</body>
</html>

14. Step 10: Configure and Run the Application

  1. Install a compatible JDK and servlet container.
  2. Install MySQL and create the student_mvc_db database and students table.
  3. Add compatible Servlet API, JDBC driver, and JSTL dependencies to the project. The Servlet API is usually provided by the container.
  4. Configure the DB_URL, DB_USER, and DB_PASSWORD environment variables.
  5. Compile the project and package it as a WAR file using Maven or your IDE.
  6. Deploy the WAR file to a compatible servlet container.
  7. Open the application and navigate to /students under the deployed application's context path.
  8. Add a student and verify that the record appears in the list.
  9. Refresh the page and confirm that the record remains stored in the database.
  10. Delete a test record and verify that it no longer appears.

Deployment steps vary according to the IDE, servlet container, Java version, and dependency configuration. Confirm that the container supports the Jakarta Servlet API version used by the application.

15. Understanding CRUD Operations

CRUD stands for Create, Read, Update, and Delete. These four operations form the foundation of many database-driven applications.

Operation SQL Statement Purpose
Create INSERT Adds a new record.
Read SELECT Retrieves existing records.
Update UPDATE Modifies an existing record.
Delete DELETE Removes a record.

Example Update Query

String sql =
    "UPDATE students SET name = ?, email = ? WHERE id = ?";

try (Connection connection = DBConnection.getConnection();
     PreparedStatement statement =
         connection.prepareStatement(sql)) {

    statement.setString(1, name);
    statement.setString(2, email);
    statement.setInt(3, id);

    int affectedRows = statement.executeUpdate();
}

Place the update query inside the DAO layer. The service layer should validate the submitted values, and the Controller should coordinate the request. A complete edit workflow also needs a method to retrieve a student by ID, a JSP form populated with existing values, and appropriate validation and error handling.

16. Database Transactions and Data Integrity

A transaction groups related database operations into a single unit. It helps ensure that changes either complete together or are rolled back when an operation fails.

For example, a course enrollment workflow may need to create an enrollment record and decrease the number of available seats. If one operation fails, the other may need to be rolled back.

try (Connection connection = DBConnection.getConnection()) {
    connection.setAutoCommit(false);

    try {
        // Execute related SQL operations using this connection.

        connection.commit();
    } catch (SQLException ex) {
        try {
            connection.rollback();
        } catch (SQLException rollbackException) {
            ex.addSuppressed(rollbackException);
        }

        throw ex;
    }
}

This is a transaction pattern illustration rather than a complete business operation. The related SQL statements must use the same connection. Production code should define clear transaction boundaries, handle rollback failures, and choose a suitable transaction isolation level.

17. Common Errors and Troubleshooting

Error Possible Cause Solution
Database connection refused MySQL is stopped or the host and port are incorrect. Check the database service, host, port, and JDBC URL.
Access denied for user Incorrect credentials or insufficient database permissions. Verify environment variables and database privileges.
Unknown database The database has not been created or the URL uses the wrong name. Create the database and verify the JDBC URL.
Table does not exist The table name or selected database is incorrect. Check the SQL schema and selected database.
Duplicate email error The email already exists and violates the UNIQUE constraint. Handle the constraint violation and display a useful message.
HTTP 404 Incorrect context path or Servlet mapping. Check the deployed application path and @WebServlet mapping.
HTTP 405 The request uses an unsupported HTTP method. Verify form methods and the Servlet's doGet() or doPost() implementation.
JSP tag library error JSTL dependency or tag URI is incompatible. Use the tag library URI and dependency version supported by the project.
Student list is empty No rows exist or the DAO query is failing. Check table data, query logic, database configuration, and server logs.
Changes are not saved An insert or update failed or a transaction was not committed. Check affected-row counts, exceptions, and transaction handling.

18. Security Best Practices

  • Use PreparedStatement: Bind input values rather than concatenating them into SQL strings.
  • Validate server-side: Never rely solely on browser-side form validation.
  • Encode output: Escape user-controlled text before displaying it in HTML.
  • Protect state changes: Use CSRF protection for insert, update, and delete forms.
  • Check authorization: Verify that the current user can access or modify the requested record.
  • Protect credentials: Keep database passwords out of source code and version control.
  • Use least privilege: Give the database account only the permissions required by the application.
  • Use HTTPS: Encrypt traffic between the browser and server.
  • Handle errors safely: Do not expose SQL statements, credentials, or stack traces to users.
  • Use connection pooling: Prefer a managed or configured connection pool in production.
  • Log appropriately: Record technical errors without logging passwords or unnecessary sensitive data.

19. Testing the Application

Testing verifies that each layer works correctly and that the application behaves as expected when valid or invalid requests are submitted.

Suggested Test Cases

Test Case Expected Result
Add a student with valid details. The record is inserted and appears in the list.
Submit an empty name. Validation prevents insertion.
Submit an invalid email format. The service rejects the input.
Submit an email that already exists. The database rejects the duplicate and the application handles the error.
Open the student listing page. Existing records are retrieved and displayed.
Delete an existing student. The record is removed after the request is authorized and processed.
Delete a nonexistent student ID. The application reports that no matching record was found.
Stop the database and submit a request. The application returns a safe error response and logs technical details.
Enter HTML-like text in a name field. The displayed value is encoded and is not executed as HTML or JavaScript.

20. Best Practices for Maintainable MVC Applications

  • Keep request-handling logic inside Servlets.
  • Keep presentation markup inside JSP pages.
  • Use JavaBeans to represent structured data.
  • Put business rules in service classes.
  • Put SQL operations in DAO or repository classes.
  • Use meaningful names for methods, attributes, packages, and database columns.
  • Use request scope for data needed during a single request.
  • Use Post/Redirect/Get after successful state-changing form submissions.
  • Use a connection pool in production environments.
  • Use transactions for operations that must succeed or fail together.
  • Test service logic separately from Servlet request handling.
  • Keep framework dependencies compatible with the target runtime.

21. Practical Exercises

Exercise 1: Add Student Search

Add a search form that accepts a student's name or email. Create a DAO method using a parameterized SELECT query and display matching records.

Exercise 2: Implement Update Functionality

Add an edit action that retrieves an existing student by ID, fills a JSP form, validates submitted values, and updates the database.

Exercise 3: Handle Duplicate Email Addresses

Handle database unique-constraint violations and display a helpful validation message without exposing database internals.

Exercise 4: Introduce Pagination

Modify the listing query to retrieve a limited number of rows per page. Add page navigation and validate page parameters on the server.

Exercise 5: Add User Authentication

Implement a secure authentication flow and protect student-management operations using server-side authorization checks. Never store plain-text passwords.

Exercise 6: Build a Course Enrollment Application

Create tables for courses and enrollments, then implement enrollment using a transaction so that related database updates remain consistent.

22. Interview Questions and Answers

Q1. What is a database-driven MVC web application?

Answer: It is a web application that separates request handling, business logic, presentation, and database access while using a database for persistent storage.

Q2. What is the role of a Servlet?

Answer: A Servlet receives HTTP requests, reads input, calls application logic, sets attributes, and forwards or redirects to the appropriate destination.

Q3. Why should SQL queries not be written inside JSP pages?

Answer: SQL in JSP mixes persistence logic with presentation. A DAO layer keeps database operations separate and improves maintainability and testability.

Q4. What is JDBC?

Answer: JDBC is a Java API that provides interfaces and classes for connecting to databases and executing SQL statements.

Q5. What is the DAO pattern?

Answer: DAO separates data-access logic from business and presentation logic. It commonly contains methods for inserting, retrieving, updating, and deleting records.

Q6. What is a PreparedStatement?

Answer: It is a JDBC object for executing parameterized SQL statements. It separates SQL structure from input values and helps reduce SQL injection risks.

Q7. What is the difference between executeQuery() and executeUpdate()?

Answer: executeQuery() is used for queries that return a ResultSet, usually SELECT statements. executeUpdate() is commonly used for INSERT, UPDATE, and DELETE operations and returns an affected-row count.

Q8. What is connection pooling?

Answer: Connection pooling reuses database connections instead of creating a new physical connection for every request, improving resource management and performance.

Q9. Why is try-with-resources useful in JDBC?

Answer: It automatically closes resources such as connections, statements, and result sets when the block completes or an exception occurs.

Q10. What is a database transaction?

Answer: A transaction groups operations into a unit of work. Commit saves the changes, while rollback cancels uncommitted changes when an operation fails.

Q11. What is the Post/Redirect/Get pattern?

Answer: After processing a successful POST request, the server redirects the browser to a GET endpoint. This reduces accidental repeated submissions when refreshing the result page.

Q12. How can a Java MVC application prevent SQL injection?

Answer: Use prepared statements with bound parameters, avoid SQL concatenation with untrusted input, and apply suitable database permissions.

Q13. How do Servlets pass data to JSP?

Answer: Servlets can place objects in request attributes using request.setAttribute() and forward the request to a JSP that reads the attributes using Expression Language.

Q14. Why is validation required at both application and database levels?

Answer: Application validation gives users meaningful feedback and enforces business rules. Database constraints provide an additional layer of integrity for stored records.

Q15. What is the purpose of a service layer?

Answer: It centralizes business rules, coordinates DAO operations, and provides reusable methods that can be tested independently of HTTP handling.

23. Quick Revision Checklist

  • MVC separates Model, View, and Controller responsibilities.
  • Servlets handle HTTP requests and coordinate application flow.
  • JSP pages display dynamic HTML.
  • JavaBeans represent structured application data.
  • Service classes implement business rules.
  • DAO classes execute database operations.
  • JDBC connects Java code to a relational database.
  • Prepared statements bind user-supplied values safely.
  • CRUD means Create, Read, Update, and Delete.
  • Transactions help maintain consistency across related operations.
  • Request attributes pass data to JSP during the same request.
  • PRG helps reduce accidental repeated form submissions.
  • Server-side validation, output encoding, CSRF protection, and authorization are essential security measures.

24. Conclusion

Building a database-driven MVC web application combines Java Servlets, JSP, JavaBeans, JDBC, and a relational database into a structured application. The Servlet handles requests, the service layer applies business rules, the DAO manages SQL operations, and JSP renders the resulting data.

The Student Management System demonstrates database connectivity, CRUD operations, validation, error handling, and separation of responsibilities. The same architecture can be extended to inventory management, employee records, course enrollment, product catalogs, and many other data-driven applications.

25. Related Learning Resources

Previous Next
whatsapp